package uem

import (
	"errors"
	"fmt"
	"github.com/nats-io/nats-server/v2/server"
	nats "github.com/nats-io/nats.go"
	"go.uber.org/automaxprocs/maxprocs"
	"time"
)

type SMQEventMsgFunc func(event int)
type SMQRecvMsgFunc func(reply string, date []byte)
type SMQC_ReConnectFunc func(nc *nats.Conn)
type SMQC_ReCloseFunc func(nc *nats.Conn)
type SMQC_ErrorFunc func(nc *nats.Conn, err error)

type SMQServer struct {
	srv *server.Server
}

type SMQClient struct {
	nc           *nats.Conn
	name         string
	recvhandler  SMQRecvMsgFunc
	replyhandler SMQRecvMsgFunc
	eventhandler SMQEventMsgFunc
	connected    int
}

func NewMQClient(addr string, port int, name string, network string) (*SMQClient, error) {

	var err error
	smqc := &SMQClient{}

	nataddr := fmt.Sprintf("nats://%s:%d", addr, port)

	smqc.nc, err = nats.Connect(nataddr, nats.Name(name),
		//nats.ReconnectHandler(C_ReConnectFunc),
		//nats.ClosedHandler(C_ReCloseFunc),
		//nats.DisconnectErrHandler(C_ErrorFunc),
		nats.ReconnectWait(time.Second),
		nats.MaxReconnects(3600),
		nats.Timeout(5*time.Second))

	if err != nil {
		return nil, err
	}

	smqc.connected = 1
	return smqc, nil
}

func setMQOptions(addr string, port int) *server.Options {
	return &server.Options{
		Host: addr,
		Port: port,
		//HTTPPort: -1,
		//Cluster:  server.ClusterOpts{Port: -1, Name: name},
		NoLog:  false,
		NoSigs: true,
		Debug:  true,
		Trace:  true,
	}
}

func (c *SMQClient) GetNC() *nats.Conn {
	return c.nc
}

func NewMQServer(addr string, port int) (*SMQServer, error) {

	var err error
	smqs := &SMQServer{}
	opts := setMQOptions(addr, port)
	smqs.srv, err = server.NewServer(opts)
	if err != nil {
		return nil, err
	}
	return smqs, nil
}
func (s *SMQServer) MQServerRun() error {

	var err error
	if server.Run(s.srv); err != nil {
		return err
	}
	undo, err := maxprocs.Set(maxprocs.Logger(s.srv.Debugf))

	if err != nil {
		return errors.New("Failed to set GOMAXPROCS")
	} else {
		defer undo()
	}

	s.srv.WaitForShutdown()
	return nil
}
func (s *SMQServer) CloseMQServer() {
	s.srv.Shutdown()
}
func (c *SMQClient) CloseMQClient() {
	c.nc.Close()
}
func (c *SMQClient) SetEventHandler(event SMQEventMsgFunc) {
	c.eventhandler = event
}
func (c *SMQClient) PublishMsg(subj string, msg []byte) error {

	if err := c.nc.Publish(subj, msg); err != nil {
		return err
	}
	return c.nc.Flush()
}
func (c *SMQClient) RequestMsg(subj string, msg []byte) error {

	if _, err := c.nc.Request(subj, msg, 5*time.Second); err != nil {
		return err
	}
	return c.nc.Flush()
}

func (c *SMQClient) RecvMsgHandler(msg *nats.Msg) {
	c.recvhandler(msg.Reply, msg.Data)
}
func (c *SMQClient) SubscribeMsg(subj string, v SMQRecvMsgFunc) error {

	c.recvhandler = v
	if _, err := c.nc.Subscribe(subj, c.RecvMsgHandler); err != nil {
		return err
	}
	return c.nc.Flush()
}
func (c *SMQClient) ReplyMsgHandler(msg *nats.Msg) {
	msg.Ack()
	c.replyhandler(msg.Reply, msg.Data)
}
func (c *SMQClient) ReplyMsg(subj string, v SMQRecvMsgFunc) error {

	c.replyhandler = v
	if _, err := c.nc.Subscribe(subj, c.ReplyMsgHandler); err != nil {
		return err
	}
	return c.nc.Flush()
}
